﻿#pragma once

NS_CR_BEGIN

template<typename T>
struct no_const 
{
	using type = typename _STD conditional<_STD is_const<T>::value, typename _STD remove_const<T>::type, T>::type;
};

/*
* RAII方式管理申请和释放资源的类
* 对象创建时,执行acquire(申请资源)动作(可以为空函数[]{})
* 对象析构时,执行release(释放资源)动作
* 禁止对象拷贝和赋值
*/
template<typename T = void>
class raii
{
public:
	using fun_type = _STD function<T()>;
	explicit raii(fun_type release, fun_type acquire = []()->T {}, bool default_com = true) NOEXCEPT
		: _commit(default_com)
		, _release(release) 
	{
		acquire();
	}

	raii(raii&& rv) NOEXCEPT
		: _commit(rv._commit)
		, _release(rv._release)
	{
		rv._commit = false;
	}

	raii(const raii&) = delete;

	raii& operator = (const raii&) = delete;

	raii& commit(bool c = true) NOEXCEPT
	{
		_commit = c;
		return *this;
	}

	~raii() NOEXCEPT
	{
		if (_commit)
		{
			_release();
		}
	}

private:
	bool _commit;
protected:
	_STD function<T()> _release;
};

/* 
* 用于实体资源的raii管理类
* T为资源类型
* acquire为申请资源动作，返回资源T
* release为释放资源动作, 释放资源T
*/

template<typename T>
class raii_var
{
public:
	using _Self = raii_var<T>;
	using acq_type = std::function<T()>;
	using rel_type = std::function<void(T&)>;

	explicit raii_var(acq_type acquire, rel_type release) NOEXCEPT
		: _resource(acquire())
		, _release(release)
	{}

	raii_var(raii_var&& rv)
		: _resource(std::move(rv._resource))
		, _release(std::move(rv._release))
	{
		rv._commit = false;
	}

	~raii_var() NOEXCEPT
	{
		if (_commit)
		{
			_release(_resource);
		}
	}

	_Self& commit(bool c = true) NOEXCEPT
	{
		_commit = c;
		return *this;
	}

	T& get() NOEXCEPT
	{
		return _resource;
	}

	T& operator*() NOEXCEPT
	{
		return get();
	}

	template<typename _T = T>
	typename std::enable_if<std::is_pointer<_T>::value, _T>::type operator->() const NOEXCEPT
	{
		return _resource;
	}

	template<typename _T = T>
	typename std::enable_if<std::is_class<_T>::value, _T*>::type operator->() const NOEXCEPT
	{
		return std::addressof(_resource);
	}
private:
	bool		_commit = true;
	T			_resource;
	rel_type	_release;
};

/* 
* 创建 raii 对象,
* 用std::bind将M_REL,M_ACQ封装成std::function<void()>创建raii对象
* RES      资源类型
* M_REL    释放资源的成员函数地址
* M_ACQ    申请资源的成员函数地址
*/

template<typename RE_TYPE = void, typename RES, typename M_REL, typename M_ACQ>
raii<RE_TYPE> make_raii(RES & res, M_REL rel, M_ACQ acq, bool default_com = true) NOEXCEPT
{
	static_assert(std::is_class<RES>::value, "RES is not a class or struct type.");
	static_assert(std::is_member_function_pointer<M_REL>::value, "M_REL is not a member function.");
	static_assert(std::is_member_function_pointer<M_ACQ>::value, "M_ACQ is not a member function.");
	CR_ASSERT(nullptr != rel && nullptr != acq);
	auto p_res = std::addressof(const_cast<typename no_const<RES>::type&>(res));
	return raii<RE_TYPE>(std::bind(rel, p_res), std::bind(acq, p_res), default_com);
}

/* 创建 raii 对象 无需M_ACQ的简化版本 */
template<typename RE_TYPE = void, typename RES, typename M_REL>
raii<RE_TYPE> make_raii(RES & res, M_REL rel, bool default_com = true) NOEXCEPT
{ 
	static_assert(std::is_class<RES>::value, "RES is not a class or struct type.");
	static_assert(std::is_member_function_pointer<M_REL>::value, "M_REL is not a member function.");
	CR_ASSERT(nullptr != rel);
	auto p_res = std::addressof(const_cast<typename no_const<RES>::type&>(res));
	return raii<RE_TYPE>(std::bind(rel, p_res), [] {}, default_com);
}

NS_CR_END
